package com.always.electrical.energy.config;

import com.always.electrical.energy.mqtt.res.MqttResponse;
import com.always.electrical.energy.mqtt.res.MqttTaskRes;
import com.always.electrical.energy.utils.AesUtil;
import com.always.electrical.energy.utils.JsonApi;
import com.always.electrical.energy.utils.TypeRefResult;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.text.SimpleDateFormat;

@Configuration
@Slf4j
public class BeanFactory {

//    @Bean
//    public Executor executor() {
//        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//        executor.setCorePoolSize(100);
//        executor.setMaxPoolSize(200);
//        executor.setQueueCapacity(1000);
//        executor.setThreadNamePrefix("RUN_");
//        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//        executor.initialize();
//        return executor;
//    }
//
//    @Bean
//    public ScheduledExecutorService scheduledExecutorService() {
//        return new ScheduledThreadPoolExecutor(5, new ThreadFactoryBuilder().setNameFormat("scheduled-thread-%d")
//                .build());
//    }
//
//    @Bean
//    public TaskScheduler taskScheduler() {
//        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
//        threadPoolTaskScheduler.setPoolSize(Runtime.getRuntime().availableProcessors() * 2);
//        threadPoolTaskScheduler.setThreadNamePrefix("taskScheduler-");
//        threadPoolTaskScheduler.setAwaitTerminationSeconds(60);
//        threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true);
//        return threadPoolTaskScheduler;
//    }

    @Bean
    public String pwd(@Value("${web.pwd}") String pwd) {
        return AesUtil.decode(pwd);
    }

    /**
     * JSON的转换器
     */
    @Bean
    public JsonApi jsonApi() {
        ObjectMapper objectMapper = new ObjectMapper()
                .setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))
                .setSerializationInclusion(JsonInclude.Include.NON_NULL)
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
                .registerModule(new JavaTimeModule());
        return new JsonApi() {
            @Override
            @Nonnull
            public String toJson(@Nullable Object data) {
                try {
                    if (null == data) {
                        return "";
                    }
                    return objectMapper.writeValueAsString(data);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }

            @Override
            @Nonnull
            public <T> T fromJson(@Nullable String json, @Nonnull Class<T> clazz) {
                try {
                    if (Strings.isEmpty(json)) {
                        return clazz.newInstance();
                    }
                    return objectMapper.readValue(json, clazz);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }

            @Nonnull
            @Override
            public <RES extends MqttResponse> MqttTaskRes<RES> fromJsonTypeRef(@Nullable String json, @Nonnull Class<RES> clazz) {
                try {
                    return objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                            .readValue(json, new TypeRefResult<>(objectMapper, clazz));
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }

            @Nonnull
            @Override
            public JsonNode readTree(@Nullable String json) {
                try {
                    return objectMapper.readTree(json);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        };
    }
}
